﻿#include <QApplication>
#include <QPainter>
#include <QStyle>
#include <QStyledItemDelegate>
#include <QHeaderView>
#include <QDebug>
#include <QFocusEvent>
#include <QFileInfo>
#include <QFileDialog>
#include <QMetaType>
#include <QMetaEnum>
#include "JZPropertyBrowser.h"
#include "JZPropertyWidget.h"

static int variantTypeId(const QVariant &var)
{
    if (var.type() == QVariant::UserType)
        return var.userType();
    else
        return var.type();
}

class JZPropertyItemDelegate : public QStyledItemDelegate
{
public:
    JZPropertyItemDelegate(QObject *parent)
        :QStyledItemDelegate(parent)
    {
    }

    virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {        
        if (index.column() == 0)
            return nullptr;
        
        auto prop = browser->property(index);
        if (prop->dataType() == QVariant::Invalid)
            return nullptr;

        auto widget = prop->createEditWidget();
        widget->setParent(parent);        
        return widget;
    }

    void setModelData(QWidget *editor,
        QAbstractItemModel *model,
        const QModelIndex &index) const override
    {        
        auto edit = qobject_cast<JZPropertyWidget*>(editor);
        edit->deleteLater();

        auto prop = browser->property(index);
        QVariant v = edit->value();
        if (!v.isValid())
            return;
        
        if (v != prop->value())
        {
            prop->setValue(v);

            auto send_prop = prop;
            while (send_prop->isSub())
            {
                send_prop = send_prop->parent();
            }
            emit browser->valueChanged(send_prop, send_prop->value());
        }
    }

    void paint(QPainter *painter, const QStyleOptionViewItem &option,
        const QModelIndex &index) const
    {
        QStyledItemDelegate::paint(painter, option, index);

        QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &option));
        painter->save();
        painter->setPen(QPen(color));
        if (index.column() == 0) {
            int right = (option.direction == Qt::LeftToRight) ? option.rect.right() : option.rect.left();
            painter->drawLine(right, option.rect.y(), right, option.rect.bottom());
        }
        painter->restore();
    }

    void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
        const QModelIndex &index) const
    {
        editor->setGeometry(option.rect.adjusted(0, 0, 0, -1));
    }

    JZPropertyBrowser *browser;
};

//JZProperty
JZProperty::JZProperty(QString name, int dataType)
{        
    m_item = nullptr;
    m_enabled = true;
    m_flag = Prop_none;
    m_name = name;
    m_dataType = dataType;    
    m_parent = nullptr;
}

const QString &JZProperty::name() const
{
    return m_name;
}

void JZProperty::setName(const QString &name)
{
    m_name = name;
    if (m_item)
        m_item->setText(0, name);
}

int JZProperty::dataType() const
{
    return m_dataType;
}

void JZProperty::setDataType(int dataType)
{
    m_dataType = dataType;
}

JZPropertyWidget *JZProperty::createEditWidget()
{
    if (m_dataType == qMetaTypeId<QString>())
        return new JZPropertyLineWidget(this);
    else if (m_dataType == qMetaTypeId<bool>())
    {
        QVariantList valueList = { false,true };
        QStringList dispList = {"false","true"};
        return new JZPropertyComboBoxWidget(this,valueList,dispList);
    }
    else if(m_dataType == qMetaTypeId<int8_t>()
        || m_dataType == qMetaTypeId<uint8_t>()
        || m_dataType == qMetaTypeId<int16_t>()
        || m_dataType == qMetaTypeId<uint16_t>()
        || m_dataType == qMetaTypeId<int>())
    {
        JZPropertySpinBoxWidget *w = new JZPropertySpinBoxWidget(this);
        if(m_min.isValid())
            w->spinBox()->setMinimum(m_min.toInt());
        if(m_max.isValid())
            w->spinBox()->setMinimum(m_max.toInt());
        return w;
    }
    else if(m_dataType == qMetaTypeId<float>() || m_dataType == qMetaTypeId<double>())
        return new JZPropertyDoubleSpinBoxWidget(this);
    else if (QMetaType(m_dataType).flags().testFlag(QMetaType::IsEnumeration))
    {
        QMetaType meta_type(m_dataType);
        QString enum_name = meta_type.name();
        int gap_idx = enum_name.indexOf("::");
        if (gap_idx > 0)
            enum_name = enum_name.mid(gap_idx + 2);

        QVariantList valueList;
        QStringList dispList;

        auto meta_obj = meta_type.metaObject();
        for (int i = 0; i < meta_obj->enumeratorCount(); i++)
        {
            auto e = meta_obj->enumerator(i);
            if (e.enumName() == enum_name)
            {
                for (int key_idx = 0; key_idx < e.keyCount(); key_idx++)
                {
                    QVariant v;
                    v.create(m_dataType, nullptr);
                    int *ptr = (int*)v.data();
                    *ptr = e.value(key_idx);
                    valueList << v;
                    dispList << e.key(key_idx);
                }                
                break;
            }
        }        
        return new JZPropertyComboBoxWidget(this,valueList, dispList);
    }
    else
    {
        Q_ASSERT(0);
    }

    return nullptr;
}

QIcon JZProperty::displayIcon()
{
    return QIcon();
}

QString JZProperty::displayText()
{
    return m_value.toString();
}

bool JZProperty::isEnabled() const
{
    return m_enabled;
}

void JZProperty::setEnabled(bool flag)
{
    m_enabled = flag;
    if (m_item) {
        auto tree = qobject_cast<JZPropertyBrowser*>(m_item->treeWidget());
        tree->setItemEnabled(m_item, flag);
    }    
}

void JZProperty::setVisible(bool flag)
{
    m_item->setHidden(!flag);
}

bool JZProperty::isVisible()
{
    return !m_item->isHidden();
}

void JZProperty::setEditable(bool flag)
{
    if (!flag)
        m_flag |= Prop_NoEdit;
    else
        m_flag &= (~Prop_NoEdit);
}

bool JZProperty::isEditable()
{
    return !(m_flag & Prop_NoEdit);
}

void JZProperty::addSubProperty(JZProperty *prop)
{
    Q_ASSERT(!prop->parent());
    prop->m_parent = this;
    m_childs.push_back(QSharedPointer<JZProperty>(prop));
    if (m_item)
    {
        auto tree = qobject_cast<JZPropertyBrowser*>(m_item->treeWidget());
        tree->createPropItem(m_item, prop);
    }
}

JZProperty *JZProperty::parent()
{
    return m_parent;
}

JZProperty* JZProperty::child(int index)
{
    return m_childs[index].data();
}

int JZProperty::flag() const
{
    return m_flag;
}

void JZProperty::setFlag(int flag)
{
    m_flag = flag;
}

bool JZProperty::isSub() const
{
    return m_flag & Prop_Sub;
}

void JZProperty::setValue(const QVariant &value)
{
    Q_ASSERT_X(variantTypeId(value) == m_dataType, "Invalid type: ",
        qPrintable(QString("require %0,but give %1").arg(QMetaType(m_dataType).name(), value.typeName())));

    m_value = value;
    if(m_item)
    {
        auto tree = qobject_cast<JZPropertyBrowser*>(m_item->treeWidget());        
        tree->updateItem(m_item);
    }
}

const QVariant& JZProperty::value() const
{
    return m_value;
}

void JZProperty::setRange(QVariant min, QVariant max)
{
    m_min = min;
    m_max = max;
}

QVariant JZProperty::minValue()
{
    return m_min;
}

QVariant JZProperty::maxValue()
{
    return m_max;
}

//JZPropertyGroup
JZPropertyGroup::JZPropertyGroup(QString name)
    :JZProperty(name, QVariant::Invalid)
{
}

//JZPropertyEnum
JZPropertyEnum::JZPropertyEnum(QString name, int dataType, QVariantList enmuList, QStringList enumTextList)
    : JZProperty(name, dataType)
{
    m_enumList = enmuList;
    m_enumTextList = enumTextList;
    if(enmuList.size() > 0)
        m_value = enmuList[0];
}

QVariantList JZPropertyEnum::enumList()
{
    return m_enumList;
}

QStringList JZPropertyEnum::enumTextList()
{
    return m_enumTextList;
}

JZPropertyWidget *JZPropertyEnum::createEditWidget()
{
    return new JZPropertyComboBoxWidget(this, m_enumList, m_enumTextList);
}

QString JZPropertyEnum::displayText()
{
    int index = m_enumList.indexOf(m_value);
    if (index != -1)
        return m_enumTextList[index];
    else
        return QString();
}

//JZPropertyIntEnum
JZPropertyIntEnum::JZPropertyIntEnum(QString name, QList<int> enmuList, QStringList enumTextList)
    :JZPropertyEnum(name, QMetaType::Int, QVariantList(), QStringList())
{
    for(int i = 0; i < enmuList.size(); i++)
        m_enumList << enmuList[i];
        
    m_enumTextList = enumTextList;
    m_value = m_enumList[0];
}

//JZPropertyStringEnum
JZPropertyStringEnum::JZPropertyStringEnum(QString name, QStringList enumTextList)
    :JZPropertyEnum(name, QMetaType::QString, QVariantList(), QStringList())
{
    for(int i = 0; i < enumTextList.size(); i++)
        m_enumList << enumTextList[i];
    
    m_enumTextList = enumTextList;
    m_value = m_enumList[0];
}

//JZPropertyFilePath
JZPropertyFilePath::JZPropertyFilePath(QString name, QString filter)
    :JZProperty(name, QMetaType::QString)
{    
    m_fileFilter = filter;
}

QString JZPropertyFilePath::displayText()
{
    QFileInfo info(m_value.toString());
    return info.fileName();
}

JZPropertyWidget *JZPropertyFilePath::createEditWidget()
{
    JZPropertyDialogWidget* w = new JZPropertyDialogWidget(this);
    w->showFunction = [this](JZPropertyDialogWidget* w)->QVariant {
        QString cur_path = w->prop()->value().toString();
        QString path = QFileDialog::getOpenFileName(w, "Select File", cur_path, this->m_fileFilter);
        if (!path.isEmpty())
            return path;
        else
            return QVariant();
    };
    return w;
}

QString JZPropertyFilePath::fileFilter()
{
    return m_fileFilter;
}

void JZPropertyFilePath::setFileFilter(QString filter)
{
    m_fileFilter = filter;
}

//JZPropertyDir
JZPropertyDir::JZPropertyDir(QString name)
    :JZProperty(name, QMetaType::QString)
{    
}

QString JZPropertyDir::displayText()
{
    return m_value.toString();
}

JZPropertyWidget *JZPropertyDir::createEditWidget()
{
    JZPropertyDialogWidget* w = new JZPropertyDialogWidget(this);
    w->showFunction = [this](JZPropertyDialogWidget* w)->QVariant {
        QString cur_path = w->prop()->value().toString();
        QString path = QFileDialog::getExistingDirectory(w, "Select Dir", cur_path);
        if (!path.isEmpty())
            return path;
        else
            return QVariant();
    };
    return w;
}

//JZPropertyPoint
JZPropertyPoint::JZPropertyPoint(QString name, int dataType)
    :JZProperty(name, dataType)
{
    m_flag = Prop_NoEdit;

    int sub_type = (dataType == qMetaTypeId<QPoint>()) ? qMetaTypeId<int>() : qMetaTypeId<double>();
    JZProperty* prop_x = new JZProperty("x", sub_type);
    JZProperty* prop_y = new JZProperty("y", sub_type);
    prop_x->setFlag(Prop_Sub);
    prop_y->setFlag(Prop_Sub);
    addSubProperty(prop_x);
    addSubProperty(prop_y);
}

QString JZPropertyPoint::displayText()
{
    QString x = this->child(0)->value().toString();
    QString y = this->child(1)->value().toString();
    return x + " x " + y;
}

void JZPropertyPoint::setValue(const QVariant& value)
{
    if (dataType() == qMetaTypeId<QPoint>())
    {
        QPoint pt = value.toPoint();
        m_childs[0]->setValue(pt.x());
        m_childs[1]->setValue(pt.y());
    }
    else
    {
        QPointF pt = value.toPointF();
        m_childs[0]->setValue(pt.x());
        m_childs[1]->setValue(pt.y());
    }        
}

const QVariant& JZPropertyPoint::value() const
{
    QVariant *ptr = const_cast<QVariant*>(&m_value);
    if (dataType() == qMetaTypeId<QPoint>())
    {
        int x = m_childs[0]->value().toInt();
        int y = m_childs[1]->value().toInt();
        *ptr = QPoint(x, y);
    }
    else
    {
        double x = m_childs[0]->value().toDouble();
        double y = m_childs[1]->value().toDouble();
        *ptr = QPoint(x, y);
    }
    return m_value;
}

//JZPropertyRect
JZPropertyRect::JZPropertyRect(QString name, int dataType)
    :JZProperty(name, dataType)
{
    m_flag = Prop_NoEdit;

    int sub_type = (dataType == qMetaTypeId<QRect>()) ? qMetaTypeId<int>() : qMetaTypeId<double>();
    JZProperty* prop_x = new JZProperty("x", sub_type);
    JZProperty* prop_y = new JZProperty("y", sub_type);
    JZProperty* prop_w = new JZProperty("width", sub_type);
    JZProperty* prop_h = new JZProperty("height", sub_type);
    prop_x->setFlag(Prop_Sub);
    prop_y->setFlag(Prop_Sub);
    prop_w->setFlag(Prop_Sub);
    prop_h->setFlag(Prop_Sub);
    addSubProperty(prop_x);
    addSubProperty(prop_y);
    addSubProperty(prop_w);
    addSubProperty(prop_h);
}

QString JZPropertyRect::displayText()
{
    QString x = this->child(0)->value().toString();
    QString y = this->child(1)->value().toString();
    QString w = this->child(2)->value().toString();
    QString h = this->child(3)->value().toString();
    return QString("{ %0, %1, %2, %3 }").arg(x,y,w,h);
}

void JZPropertyRect::setValue(const QVariant& value)
{
    if (dataType() == qMetaTypeId<QPoint>())
    {
        QRect pt = value.toRect();
        m_childs[0]->setValue(pt.x());
        m_childs[1]->setValue(pt.y());
        m_childs[2]->setValue(pt.width());
        m_childs[3]->setValue(pt.height());
    }
    else
    {
        QRectF pt = value.toRectF();
        m_childs[0]->setValue(pt.x());
        m_childs[1]->setValue(pt.y());
        m_childs[2]->setValue(pt.width());
        m_childs[3]->setValue(pt.height());
    }

}

const QVariant& JZPropertyRect::value() const
{
    QVariant *ptr = const_cast<QVariant*>(&m_value);
    if (dataType() == qMetaTypeId<QPoint>())
    {
        int x = m_childs[0]->value().toInt();
        int y = m_childs[1]->value().toInt();
        int w = m_childs[2]->value().toInt();
        int h = m_childs[3]->value().toInt();
        *ptr = QRect(x, y, w, h);
    }
    else
    {
        double x = m_childs[0]->value().toDouble();
        double y = m_childs[1]->value().toDouble();
        double w = m_childs[2]->value().toDouble();
        double h = m_childs[3]->value().toDouble();
        *ptr = QRectF(x, y, w, h);
    }
    return m_value;
}

//JZPropertySize
JZPropertySize::JZPropertySize(QString name, int dataType)
    :JZProperty(name, dataType)
{
    m_flag = Prop_NoEdit;

    int sub_type = (dataType == qMetaTypeId<QPoint>()) ? qMetaTypeId<int>() : qMetaTypeId<double>();
    JZProperty* prop_w = new JZProperty("width", sub_type);
    JZProperty* prop_h = new JZProperty("height", sub_type);
    prop_w->setFlag(Prop_Sub);
    prop_h->setFlag(Prop_Sub);
    addSubProperty(prop_w);
    addSubProperty(prop_h);
}

QString JZPropertySize::displayText()
{
    QString w = this->child(0)->value().toString();
    QString h = this->child(1)->value().toString();
    return w + " x " + h;
}

void JZPropertySize::setValue(const QVariant& value)
{
    if (dataType() == qMetaTypeId<QSize>())
    {
        QSize pt = value.toSize();
        m_childs[0]->setValue(pt.width());
        m_childs[1]->setValue(pt.height());
    }
    else
    {
        QSizeF pt = value.toSizeF();
        m_childs[0]->setValue(pt.width());
        m_childs[1]->setValue(pt.height());
    }
}

const QVariant& JZPropertySize::value() const
{
    QVariant* ptr = const_cast<QVariant*>(&m_value);
    if (dataType() == qMetaTypeId<QSize>())
    {
        int w = m_childs[0]->value().toInt();
        int h = m_childs[1]->value().toInt();
        *ptr = QSize(w, h);
    }
    else
    {
        double w = m_childs[0]->value().toInt();
        double h = m_childs[1]->value().toInt();
        *ptr = QSizeF(w, h);
    }
    return m_value;
}

//JZPropertyAlign
JZPropertyAlign::JZPropertyAlign(QString name)
    :JZProperty(name, qMetaTypeId<Qt::Alignment>())
{
    m_flag = Prop_NoEdit;

    m_hText = QStringList{ "AlignLeft","AlignHCenter", "AlignRight" };
    m_hValue = QList<int>{ Qt::AlignLeft,Qt::AlignHCenter,Qt::AlignRight };
    m_vText = QStringList{ "AlignTop","AlignVCenter", "AlignBottom" };
    m_vValue = QList<int>{ Qt::AlignTop,Qt::AlignVCenter,Qt::AlignBottom };


    JZProperty* prop_h = new JZPropertyIntEnum("水平", m_hValue, m_hText);
    JZProperty* prop_v = new JZPropertyIntEnum("垂直", m_vValue, m_vText);
    prop_h->setFlag(Prop_Sub);
    prop_v->setFlag(Prop_Sub);
    addSubProperty(prop_h);
    addSubProperty(prop_v);
}

QString JZPropertyAlign::displayText()
{
    int h_idx = this->child(0)->value().toInt();
    int v_idx = this->child(1)->value().toInt();
    return m_hText[h_idx] + ", " + m_vText[v_idx]; 
}

void JZPropertyAlign::setValue(const QVariant& value)
{
    Qt::Alignment align = value.value<Qt::Alignment>();
    int h_idx = align & ~(Qt::AlignTop | Qt::AlignBottom | Qt::AlignVCenter);
    int v_idx = align & ~(Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter);    
    m_childs[0]->setValue(h_idx);
    m_childs[1]->setValue(v_idx);
}

const QVariant& JZPropertyAlign::value() const
{
    QVariant* ptr = const_cast<QVariant*>(&m_value);
    int h_idx = m_childs[0]->value().toInt();
    int v_idx = m_childs[1]->value().toInt();
    Qt::Alignment align = (Qt::Alignment)(h_idx | v_idx);
    *ptr = QVariant::fromValue(align);
    return m_value;
}

//JZPropertyColor
JZPropertyColor::JZPropertyColor(QString name)
    :JZProperty(name, qMetaTypeId<QColor>())
{
    m_flag = Prop_NoEdit;

    JZProperty* prop_r = new JZProperty("r", qMetaTypeId<uint8_t>());
    JZProperty* prop_g = new JZProperty("g", qMetaTypeId<uint8_t>());
    JZProperty* prop_b = new JZProperty("b", qMetaTypeId<uint8_t>());
    prop_r->setFlag(Prop_Sub);
    prop_g->setFlag(Prop_Sub);
    prop_b->setFlag(Prop_Sub);  
    addSubProperty(prop_r);
    addSubProperty(prop_g);
    addSubProperty(prop_b);
}

QString JZPropertyColor::displayText()
{
    int r = this->child(0)->value().toInt();
    int g = this->child(1)->value().toInt();
    int b = this->child(1)->value().toInt();
    return QString::asprintf("%d,%d,%d",r,g,b);
}

void JZPropertyColor::setValue(const QVariant& value)
{
    QColor align = value.value<QColor>(); 
    m_childs[0]->setValue((uint8_t)align.red());
    m_childs[1]->setValue((uint8_t)align.green());
    m_childs[2]->setValue((uint8_t)align.blue());
}

const QVariant& JZPropertyColor::value() const
{
    int r = m_childs[0]->value().toInt();
    int g = m_childs[1]->value().toInt();
    int b = m_childs[2]->value().toInt();
    const_cast<QVariant&>(m_value) = QVariant::fromValue(QColor(r,g,b));
    return m_value;
}

//JZPropertyManager    
JZPropertyManager* JZPropertyManager::instance()
{
    static JZPropertyManager inst;
    return &inst;
}
 
JZPropertyManager::JZPropertyManager()
{
    registProp(qMetaTypeId<QSize>(), [](QString name)->JZProperty* { return new JZPropertySize(name, qMetaTypeId<QSize>()); });
    registProp(qMetaTypeId<QSizeF>(), [](QString name)->JZProperty* { return new JZPropertySize(name, qMetaTypeId<QSizeF>()); });
    registProp(qMetaTypeId<QPoint>(), [](QString name)->JZProperty* { return new JZPropertyPoint(name,qMetaTypeId<QPoint>()); });
    registProp(qMetaTypeId<QPointF>(), [](QString name)->JZProperty* { return new JZPropertyPoint(name, qMetaTypeId<QPointF>()); });
    registProp(qMetaTypeId<QRect>(), [](QString name)->JZProperty* { return new JZPropertyRect(name, qMetaTypeId<QRect>()); });
    registProp(qMetaTypeId<QRectF>(), [](QString name)->JZProperty* { return new JZPropertyRect(name, qMetaTypeId<QRectF>()); });
    registProp(qMetaTypeId<QColor>(), [](QString name)->JZProperty* { return new JZPropertyColor(name); });
    registProp(qMetaTypeId<Qt::Alignment>(), [](QString name)->JZProperty* { return new JZPropertyAlign(name); });
}

JZPropertyManager::~JZPropertyManager()
{
}

JZProperty *JZPropertyManager::create(int qmetaid, QString name)
{    
    if (m_propMap.contains(qmetaid))
        return m_propMap[qmetaid](name);
    else
        return new JZProperty(name, qmetaid);
}

void JZPropertyManager::registProp(int qmetaid, CreatePropertyFunc creator)
{
    m_propMap[qmetaid] = creator;
}    

//JZPropertyBrowser
JZPropertyBrowser::JZPropertyBrowser()
    :m_root("root", QVariant::Invalid)
{    
    this->setColumnCount(2);
    this->setHeaderLabels({ "name","value" });
    this->setAlternatingRowColors(true);    
    this->setEditTriggers(QAbstractItemView::AllEditTriggers);    

    JZPropertyItemDelegate *delegate = new JZPropertyItemDelegate(this);
    delegate->browser = this;
    this->setItemDelegate(delegate);    
}

JZPropertyBrowser::~JZPropertyBrowser()
{

}

void JZPropertyBrowser::clear()
{
    m_propMap.clear();
    QTreeWidget::clear();
    m_root.m_childs.clear();    
}

void JZPropertyBrowser::addProperty(JZProperty *prop)
{    
    createPropItem(this->invisibleRootItem(), prop);    
}

JZProperty *JZPropertyBrowser::property(const QModelIndex &index)
{
    auto item = itemFromIndex(index);
    return m_propMap.value(item, nullptr);
}

void JZPropertyBrowser::setItemEnabled(QTreeWidgetItem *item, bool flag)
{    
    if (flag)
        item->setFlags(item->flags() | Qt::ItemIsEditable);
    else
        item->setFlags(item->flags() & ~Qt::ItemIsEditable);    
}

void JZPropertyBrowser::createPropItem(QTreeWidgetItem *parent, JZProperty *prop)
{
    QTreeWidgetItem *item = new QTreeWidgetItem();
    item->setText(0, prop->m_name);    
    if (prop->m_enabled)
        item->setFlags(item->flags() | Qt::ItemIsEditable);
    else
        item->setFlags(item->flags() & ~Qt::ItemIsEditable);
    prop->m_item = item;
    parent->addChild(item);
    m_propMap[item] = prop;

    for (int i = 0; i < prop->m_childs.size(); i++)    
        createPropItem(prop->m_item, prop->m_childs[i].data());    
    prop->m_item->setExpanded(true);
    updateItem(prop->m_item);
}

void JZPropertyBrowser::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{    
    QTreeWidgetItem *item = this->itemFromIndex(index);

    QStyleOptionViewItem opt = option;  
    /*
    bool hasValue = (m_propMap[item]->m_type != NodeProprety_GroupId);
    if (!hasValue) {
        const QColor c = option.palette.color(QPalette::Dark);
        painter->fillRect(option.rect, c);
        opt.palette.setColor(QPalette::AlternateBase, c);
    }
    else {        
        QColor c;
        if (c.isValid()) {
            painter->fillRect(option.rect, c);
            opt.palette.setColor(QPalette::AlternateBase, c.lighter(112));
        }
    }
    */
    QTreeWidget::drawRow(painter, opt, index);
    QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
    painter->save();
    painter->setPen(QPen(color));
    painter->drawLine(opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
    painter->restore();    
}

void JZPropertyBrowser::updateItem(QTreeWidgetItem *item)
{
    auto prop = m_propMap[item];
    QString text;
    
    text = prop->displayText();    
    item->setText(1, text);
    
    QIcon icon = prop->displayIcon();
    if(!icon.isNull())
        item->setIcon(1, icon);    

    if (prop->isSub())
        updateProp(prop->parent());
}

void JZPropertyBrowser::updateProp(JZProperty* prop)
{
    auto item = m_propMap.key(prop);
    updateItem(item);
}